﻿using FreeSql;
using FreeSql.Aop;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Volo.Abp;
using Volo.Abp.Modularity;
using Volo.Abp.Timing;
using Volo.Abp.Users;

namespace Colorful.Furniture.FreeSql
{
    /// <summary>
    ///  freeSqlOrm模块
    /// </summary>
    public class FurnitureFreeSqlModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            var configuration = context.Services.GetConfiguration();

            var serverProvider = context.Services.BuildServiceProvider();

            var loggerFactory = serverProvider.GetService<ILoggerFactory>();
            var log = loggerFactory?.CreateLogger<FurnitureFreeSqlModule>();

            if (!configuration.GetSection("ConnectionString").Exists())
                throw new UserFriendlyException("请在配置文件中添加ConnectionString节点");

            var connectionStringSection = configuration.GetSection("ConnectionString");

            Configure<FreeSqlOptions>(configuration.GetSection("ConnectionString"));

            var freeSqlOptions = connectionStringSection.Get<FreeSqlOptions>();

            //注入FreeSql
            var freeSql = new FreeSqlBuilder()
                .UseConnectionString(freeSqlOptions.DataType, freeSqlOptions.Default)
                .UseAutoSyncStructure(freeSqlOptions.IsAutoSyncStructure)
                .UseNoneCommandParameter(true)
                .UseMonitorCommand(cmd =>
                {
                    //log?.LogInformation($"执行的SQL语句是：{cmd.CommandText}");
                })
                .Build();

            /*
             注意：仓储过滤器属于早期功能，如果 fsql.GlobalFilter 够用的话，可以跳过以下内容。

            FreeSql.Repository 也实现了过滤器功能，它在查询时过滤，删除/修改/插入篇还会进行验证数据，避免数据安全问题。

            注意：仓储的过滤器与 IFreeSql.GlobalFilter 不是一个功能，可以同时生效。

            推荐使用 IFreeSql.GlobalFilter。仓储过滤器在早期出的功能，会一直保留。
             */
            freeSql.GlobalFilter
                .Apply<ISoftDelete>(Filter.SoftDelete, a => !a.IsDeleted);

            //添加freeSql的仓储
            context.Services.AddFreeRepository(null, typeof(FurnitureFreeSqlModule).Assembly);

            //审计日志
            freeSql.Aop.AuditValue += (_, e) =>
            {
                var serverProvider1 = context.Services.BuildServiceProvider();

                var currentUser = serverProvider1.GetService<ICurrentUser>();
                var clock = serverProvider1.GetService<IClock>();

                var propertyName = e.Property.Name.ToLower();

                //判断更新类型
                switch (e.AuditValueType)
                {
                    //新增
                    case AuditValueType.Insert:
                        e.Value = propertyName switch
                        {
                            "addtime" => clock?.Now,
                            "adduserid" => currentUser?.Id,
                            _ => e.Value
                        };
                        break;
                    case AuditValueType.Update:
                        e.Value = propertyName switch
                        {
                            "modifytime" => clock?.Now,
                            "modifyuserid" => currentUser?.Id,
                            _ => e.Value
                        };
                        break;
                    case AuditValueType.InsertOrUpdate:
                        e.Value = propertyName switch
                        {
                            "addtime" => clock?.Now,
                            "adduserid" => currentUser?.Id,
                            _ => e.Value
                        };

                        e.Value = propertyName switch
                        {
                            "modifytime" => clock?.Now,
                            "modifyuserid" => currentUser?.Id,
                            _ => e.Value
                        };
                        break;
                }
            };

            context.Services.TryAddSingleton(freeSql);
        }
    }

    /// <summary>
    ///  筛选器
    /// </summary>
    public class Filter
    {
        public const string SoftDelete = "SoftDelete";
    }
}
